package bgw

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"

	"gitee.com/liuxuezhan/ar-platform/base-common/headInfo"
	"gitee.com/liuxuezhan/ar-platform/base-common/uuid"
	"github.com/bytedance/sonic"
	"github.com/bytedance/sonic/decoder"
	"github.com/zeromicro/go-zero/core/logc"
)

type Bgw struct {
	MerchantId string
	AppId      string
	AppCode    string
	AppSecret  string
	Url        string
	NotifyUrl  string
}

func NewBgw(conf Bgw) *Bgw {
	return &Bgw{
		MerchantId: conf.MerchantId,
		AppId:      conf.AppId,
		AppCode:    conf.AppCode,
		AppSecret:  conf.AppSecret,
		Url:        conf.Url,
		NotifyUrl:  conf.NotifyUrl,
	}
}

// Payment 代收充值
func (p *Bgw) Payment(ctx context.Context, req PaymentReq) (result Response, err error) {
	// 请求第三方接口
	url := p.Url + "/api/deposit/create"
	s, _ := sonic.MarshalString(req)
	return p.SendRequest(ctx, url, s)
}

func (p *Bgw) SendRequest(ctx context.Context, url, params string) (result Response, err error) {
	// 请求 ID
	requestId := headInfo.GetTrance(ctx)
	// 随机数
	nonce := uuid.GenUUID().String()
	// 创建时间
	created := time.Now().Format(time.RFC3339)
	// 身份签名
	passwordDigest := GeneratePasswordDigest(nonce, created, p.AppSecret)
	// body 签名
	sign := GenerateBodySign(params, p.AppCode, p.AppSecret, requestId)

	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBufferString(params))
	if err != nil {
		return
	}

	// Set the appropriate headers
	req.Header.Set("Content-Type", "application/json; charset=UTF-8")
	req.Header.Set("Merchant-Id", p.MerchantId)
	req.Header.Set("Request-Id", requestId)
	req.Header.Set("Authorization", fmt.Sprintf(`WSSE realm="%s", profile="AppToken", type="v1"`, p.AppId))
	req.Header.Set("X-WSSE", fmt.Sprintf(`AppToken App="%s", PasswordDigest="%s", Nonce="%s", Created="%s"`, p.AppCode, passwordDigest, nonce, created))
	req.Header.Set("Body-Sign", fmt.Sprintf(`sign_type="HMAC-SHA256", signature="%s"`, sign))

	// Create a new HTTP client and send the request
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	// Read the response body
	bodyResp, err := io.ReadAll(resp.Body)
	if err != nil {
		return
	}

	resStr := string(bodyResp)
	headerStr, _ := sonic.MarshalString(resp.Header)

	fmt.Printf("URL: %s\nHeaderReq: %s\nData: %s\nResponse: %s\nHeaderResp: %s\n", url, req.Header, params, resStr, headerStr)
	logc.Info(ctx, fmt.Sprintf("url:%s headerReq:%s bodyReq:%s headerResp:%s bodyResp:%s", url, req.Header, params, headerStr, resStr))

	dc := decoder.NewDecoder(resStr)
	dc.UseNumber()
	dc.Decode(&result)
	if result.Code != 0 {
		return result, errors.New(result.Msg)
	}

	// 验签
	bodySign, err := ParseBodySign(resp.Header.Get("Body-Sign"))
	if err != nil {
		return result, err
	}
	respSign := GenerateBodySign(resStr, p.AppCode, p.AppSecret, resp.Header.Get("Request-Id"))
	if respSign != bodySign["signature"] {
		logc.Error(ctx, respSign, headerStr)
		return result, errors.New("Signature verification failed.")
	}

	return
}
